package com.ibatis.common.jdbc;

import com.ibatis.common.beans.Probe;
import com.ibatis.common.beans.ProbeFactory;

import com.mchange.v2.c3p0.ComboPooledDataSource;

import javax.sql.DataSource;
import java.util.Iterator;
import java.util.Map;

/**
 * Wrapper class to simplify use of C3P0
 */
public class C3P0Configuration {

    private static final Probe PROBE = ProbeFactory.getProbe();
    private DataSource dataSource;

    /**
     * Constructor to supply a map of properties
     *
     * @param properties - the map of configuration properties
     */
	public C3P0Configuration(Map properties) {
        try {
            dataSource = legacyC3P0Configuration(properties);
            if (dataSource == null) {
                dataSource = newC3P0Configuration(properties);
            }
        } catch (Exception e) {
            throw new RuntimeException("Error initializing C3P0DataSourceFactory.  Cause: " + e, e);
        }
    }

    /**
     * Getter for DataSource
     *
     * @return The DataSource
     */
    public DataSource getDataSource() {
        return dataSource;
    }

	private ComboPooledDataSource newC3P0Configuration(Map map) {
        ComboPooledDataSource basicDataSource = new ComboPooledDataSource();
        Iterator props = map.keySet().iterator();
        while (props.hasNext()) {
            String propertyName = (String) props.next();
            if (PROBE.hasWritableProperty(basicDataSource, propertyName)) {
                String value = (String) map.get(propertyName);
                Object convertedValue = convertValue(basicDataSource, propertyName, value);
                PROBE.setObject(basicDataSource, propertyName, convertedValue);
            }
        }
        return basicDataSource;
    }

	private Object convertValue(Object object, String propertyName, String value) {
        Object convertedValue = value;
        Class targetType = PROBE.getPropertyTypeForSetter(object, propertyName);
        if (targetType == Integer.class || targetType == int.class) {
            convertedValue = Integer.valueOf(value);
        } else if (targetType == Long.class || targetType == long.class) {
            convertedValue = Long.valueOf(value);
        } else if (targetType == Boolean.class || targetType == boolean.class) {
            convertedValue = Boolean.valueOf(value);
        }
        return convertedValue;
    }

	private ComboPooledDataSource legacyC3P0Configuration(Map map) throws Exception {
        ComboPooledDataSource basicDataSource = null;
        if (map.containsKey("driver")) {
            basicDataSource = new ComboPooledDataSource();
            String driver = (String) map.get("driver");
            String url = (String) map.get("url");
            String username = (String) map.get("username");
            String password = (String) map.get("password");
            //
            String initialPoolSize = (String) map.get("initialPoolSize");
            String maxPoolSize = (String) map.get("maxPoolSize");
            String minPoolSize = (String) map.get("minPoolSize");
            String acquireIncrement = (String) map.get("acquireIncrement");
            String maxIdleTime = (String) map.get("maxIdleTime");
            String maxIdleTimeExcessConnections = (String) map.get("maxIdleTimeExcessConnections");
            String maxConnectionAge = (String) map.get("maxConnectionAge");
            String maxStatements = (String) map.get("maxStatements");
            String maxStatementsPerConnection = (String) map.get("maxStatementsPerConnection");
            String numHelperThreads = (String) map.get("numHelperThreads");

            basicDataSource.setDriverClass(driver);
            basicDataSource.setJdbcUrl(url);
            basicDataSource.setUser(username);
            basicDataSource.setPassword(password);
            /*
                   basicDataSource.setMaxPoolSize(WikiGlobals.getDBMaxPoolSize());
                   basicDataSource.setMinPoolSize(WikiGlobals.getDBMinPoolSize());
                   basicDataSource.setMaxStatements(WikiGlobals.getDBMaxStatements()); //系统缓存的statement数量最大值
                   basicDataSource.setMaxStatementsPerConnection(WikiGlobals.getDBMaxStatementsPerConnection()); //每个connection缓存的statement数量最大值
                   basicDataSource.setMaxIdleTime(WikiGlobals.getDBMaxIdleTime()); //空闲连接的最大生命周期
                   basicDataSource.setNumHelperThreads(WikiGlobals.getDBNumHelperThreads()); //default:3 系统提供的JDBC操作的线程数量，可提升系统性能
                   basicDataSource.setAcquireIncrement(WikiGlobals.getDBAcquireIncrement()); //每次增量创建新连接的数量
             */

            if (notEmpty(initialPoolSize)) {
                basicDataSource.setInitialPoolSize(Integer.parseInt(initialPoolSize));
            }
            if (notEmpty(maxPoolSize)) {
                basicDataSource.setMaxPoolSize(Integer.parseInt(maxPoolSize));
            }
            if (notEmpty(minPoolSize)) {
                basicDataSource.setMinPoolSize(Integer.parseInt(minPoolSize));
            }
            if (notEmpty(acquireIncrement)) {
                basicDataSource.setAcquireIncrement(Integer.parseInt(acquireIncrement));
            }
            if (notEmpty(maxIdleTime)) {
                basicDataSource.setMaxIdleTime(Integer.parseInt(maxIdleTime));
            }
            if (notEmpty(maxIdleTimeExcessConnections)) {
                basicDataSource.setMaxIdleTimeExcessConnections(Integer.parseInt(maxIdleTimeExcessConnections));
            }
            if (notEmpty(maxConnectionAge)) {
                basicDataSource.setMaxConnectionAge(Integer.parseInt(maxConnectionAge));
            }
            if (notEmpty(maxStatements)) {
                basicDataSource.setMaxStatements(Integer.parseInt(maxStatements));
            }
            if (notEmpty(maxStatementsPerConnection)) {
                basicDataSource.setMaxStatementsPerConnection(Integer.parseInt(maxStatementsPerConnection));
            }
            if (notEmpty(numHelperThreads)) {
                basicDataSource.setNumHelperThreads(Integer.parseInt(numHelperThreads));
            }
        }
        return basicDataSource;
    }

    private boolean notEmpty(String s) {
        return s != null && s.length() > 0;
    }


    public static void main(String[] args) {
        //C3P0Configuration c3p0configuration = new C3P0Configuration();
    }
}
